home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
SMTPSERV.C
< prev
next >
Wrap
Text File
|
1993-07-22
|
10KB
|
441 lines
/* SMTP Server state machine - see RFC 821
* enhanced 4/88 Dave Trulli nn2z
*/
#include <stdio.h>
#include <ctype.h>
#include "global.h"
#include "config.h"
#include "mbuf.h"
#include "cmdparse.h"
#include "socket.h"
#include "smtp.h"
#include "files.h"
#include "bbs.h"
#ifdef NNTP
#include "nntp.h"
#endif
#ifdef LZW
#include "lzw.h"
#endif
/* Reply messages */
#ifdef LZW
static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN XLZW\n214 End\n";
#else
static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
#endif
static char SmtpBanner[] = "220 %s SMTP %s ready at %s";
static char Closing[] = "221 %s Closing\n";
static char Ok[] = "250 Ok\n";
static char Reset[] = "250 Reset state\n";
static char Sent[] = "250 Sent\n";
static char Ourname[] = "250 Hello %s, pleased to meet you\n";
#ifdef LZW
static char LZWOk[] = "252 LZW Ok\n";
#endif
static char Enter[] = "354 Enter mail, end with .\n";
static char Ioerr[] = "452 Temp file write error\n";
static char Badcmd[] = "500 Command unrecognized\n";
static char Syntax[] = "501 Syntax error\n";
static char Needrcpt[] = "503 Need RCPT (recipient)\n";
static char Unknownaddr[] = "550 <%s> address unknown\n";
static char Noalias[] = "550 No alias for <%s>\n";
/* Read the rewrite file for lines where the first word is a regular
* expression and the second word are rewriting rules.
* The special character '$' followed by a digit denotes the string that
* matched a '*' character.
* The '*' characters are numbered from 1 to 9.
*
* Example: the line "*@*.* $2@$1.ampr.org" would rewrite the address
* "foo@bar.xxx" to "bar@foo.ampr.org".
*
* $H is replaced by our hostname, and $$ is an escaped $ character.
* If the third word on the line has an 'r' character in it, the function
* will recurse with the new address.
*/
static char * near
rewrite_address(char *addr)
{
FILE *fp;
if((fp = Fopen(Rewritefile,READ_TEXT,0,0)) != NULLFILE) {
char *argv[10], buf[LINELEN], *cp, *cp2, *retstr = NULLCHAR;
int cnt;
memset(argv,0,10 * sizeof(char *));
while(fgets(buf,LINELEN,fp) != NULLCHAR) {
if(*buf == '#') {
continue;
}
if((cp = strchr(buf,' ')) == NULLCHAR) { /* get the first word */
if((cp = strchr(buf,'\t')) == NULLCHAR) {
continue;
}
}
*cp = '\0';
if((cp2 = strchr(buf,'\t')) != NULLCHAR) {
*cp = ' ';
cp = cp2;
*cp = '\0';
}
if(!wildmat(addr,buf,argv)) {
continue; /* no match */
}
rip(++cp);
retstr = mxallocw(LINELEN);
cp2 = retstr;
while(*cp != '\0' && *cp != ' ' && *cp != '\t') {
if(*cp == '$') {
if(isdigit(*(++cp))) {
if(argv[*cp - '0'-1] != '\0') {
strcat(cp2,argv[*cp - '0' - 1]);
}
}
if(*cp == 'h' || *cp == 'H') { /* Our hostname */
strcat(cp2,Hostname);
}
if(*cp == '$') { /* Escaped $ character */
strcat(cp2,"$");
}
cp2 = retstr + strlen(retstr);
cp++;
} else {
*cp2++ = *cp++;
}
}
for(cnt = 0; argv[cnt] != NULLCHAR; cnt++) {
xfree(argv[cnt]);
}
Fclose(fp);
/* If there remains an 'r' character on the line, repeat
* everything by recursing.
*/
if(strchr(cp,'r') != NULLCHAR || strchr(cp,'R') != NULLCHAR) {
if((cp2 = rewrite_address(retstr)) != NULLCHAR) {
xfree(retstr);
return cp2;
}
}
Fclose(fp);
return retstr;
}
Fclose(fp);
}
return NULLCHAR;
}
/* ------------------------ SMTP server subcmds --------------------------- */
static void near
data_command(struct smtpserv *mp)
{
if(mp->to == NULLLIST) {
usputs(mp->s,Needrcpt);
return;
} else if((mp->data = Tmpfile(0,1)) != NULLFILE) {
usputs(mp->s,Enter);
/* Add timestamp; rfc822_date adds newline */
fputs(Hdrs[RECEIVED],mp->data);
if(mp->system != NULLCHAR) {
fprintf(mp->data,"from %s ",mp->system);
}
fprintf(mp->data,"by %s with SMTP\n\tid AA%ld; %s",
Hostname,get_msgid(),rfc822_date(&currtime));
for( ; ;) {
if(recvline(mp->s,mp->buf,LINELEN) == -1) {
goto quit1;
}
rip(mp->buf);
/* check for end of message ie a . or escaped .. */
if(*mp->buf == '.') {
if(*++mp->buf == '\0') {
/* Also sends appropriate response */
usputs(mp->s,(mailit(mp->data,mp->from,mp->to) != 0) ? Ioerr : Sent);
goto quit1;
} else if (!(*mp->buf == '.' && *(mp->buf + 1) == '\0')) {
mp->buf--;
}
}
/* for UNIX mail compatiblity */
if(strncmp(mp->buf,"From ",5) == 0) {
fputc('>',mp->data);
}
/* Append to data file */
if(fprintf(mp->data,"%s\n",mp->buf) == EOF) {
goto quit;
}
}
}
quit:
usputs(mp->s,Ioerr);
quit1:
Fclose(mp->data);
mp->data = NULLFILE;
del_list(mp->to);
mp->to = NULLLIST;
}
static void near
expn_command(struct smtpserv *mp)
{
char *newaddr = NULLCHAR;
struct list *ap, *list = NULLLIST;
if(*mp->buf == '\0') {
usputs(mp->s,Syntax);
return;
}
/* rewrite address if possible */
if((newaddr = rewrite_address(mp->buf)) != NULLCHAR) {
if(strcmp(newaddr,mp->buf) != 0) {
strcpy(mp->buf,newaddr);
}
}
expandalias(&list,mp->buf);
if(strcmp(list->val,mp->buf) == 0 && list->next == NULLLIST) {
if(newaddr == NULLCHAR) {
usprintf(mp->s,Noalias,mp->buf);
del_list(list);
return;
}
}
if(newaddr != NULLCHAR) {
xfree(newaddr);
}
ap = list;
while(ap->next != NULLLIST) {
usprintf(mp->s,"250-%s\n",ap->val);
ap = ap->next;
}
usprintf(mp->s,"250 %s\n",ap->val);
del_list(list);
}
static void near
helo_command(struct smtpserv *mp)
{
if(mp->system != NULLCHAR) {
xfree(mp->system);
}
mp->system = strxdup(mp->buf);
usprintf(mp->s,Ourname,mp->system);
}
static void near
help_command(struct smtpserv *mp)
{
usputs(mp->s,Help);
}
static void near
mail_command(struct smtpserv *mp)
{
char *cp;
if((cp = getname(mp->buf)) == NULLCHAR) {
usputs(mp->s,Syntax);
return;
}
if(mp->from != NULLCHAR) {
xfree(mp->from);
}
mp->from = strxdup(cp);
mp->states = PROMPT;
}
static void near
noop_command(struct smtpserv *mp)
{
mp->states = PROMPT;
}
static void near
quit_command(struct smtpserv *mp)
{
usprintf(mp->s,Closing,Hostname);
mp->states = CLOSED;
}
static void near
rcpt_command(struct smtpserv *mp)
{
char *cp, *newaddr = NULLCHAR;
int address_type;
if((cp = getname(mp->buf)) == NULLCHAR) {
usputs(mp->s,Syntax);
return;
}
/* rewrite address if possible */
if((newaddr = rewrite_address(cp)) != NULLCHAR) {
cp = newaddr;
}
/* check if address is ok */
if((address_type = validate_address(cp)) == BADADDR) {
usprintf(mp->s,Unknownaddr,cp);
return;
}
/* if a local address check for an alias */
if(address_type == LOCAL) {
expandalias(&mp->to,cp);
} else {
/* a remote address is added to the list */
addlist(&mp->to,cp,address_type);
}
if(newaddr != NULLCHAR) {
xfree(newaddr);
}
mp->states = PROMPT;
}
static void near
rset_command(struct smtpserv *mp)
{
usputs(mp->s,Reset);
del_list(mp->to);
mp->to = NULLLIST;
}
#ifdef LZW
static void near
xlzw_command(struct smtpserv *mp)
{
if(Smtplzw) {
int lzwbits = 99;
int lzwmode = -1;
sscanf(mp->buf,"%d %d",&lzwbits,&lzwmode);
if(lzwbits > lzwmode && 9 < lzwbits && lzwbits < 17
&& (lzwmode == 0 || lzwmode == 1)) {
usputs(mp->s,LZWOk);
lzwinit(mp->s,lzwbits,lzwmode);
return;
}
}
usputs(mp->s,Badcmd);
}
#endif
void
smtpserv(int s,void *unused,void *p)
{
struct smtpserv *mp;
char *cp, *cp1;
int arglen;
static struct cmdtable {
char *name;
void near (*func) __ARGS((struct smtpserv *mp));
int states;
} cmdtable[] = {
{"DATA", data_command, 0},
{"EXPN", expn_command, 0},
{"HELO", helo_command, 0},
{"HELP", help_command, 0},
{"MAIL FROM:", mail_command, 0},
{"NOOP", noop_command, 0},
{"QUIT", quit_command, 0},
{"RCPT TO:", rcpt_command, 0},
{"RSET", rset_command, 0},
#ifdef LZW
{"XLZW", xlzw_command, 0},
#endif
{0, 0, 0},
};
struct cmdtable *cmdp;
sockmode(s,SOCK_ASCII);
sockowner(s,Curproc); /* We own it now */
mp = mxallocw(sizeof(struct smtpserv));
mp->buf = mxallocw(LINELEN);
mp->s = s;
usprintf(mp->s,SmtpBanner,Hostname,Version,ctime(&currtime));
log(mp->s,9983,"SMTP open");
for( ; ;) {
loop:
if(mp->states == CLOSED) {
break;
}
if(mp->states == PROMPT) {
usputs(mp->s,Ok);
}
mp->states = OK;
if(recvline(mp->s,mp->buf,LINELEN) <= 0) {
/* He closed on us */
break;
}
rip(mp->buf);
for(cp = mp->buf; *cp && isspace(*cp); cp++) ;
for(cp1 = cp, arglen = 0; *cp1 && *cp1 != ':'; cp1++, arglen++) {
if(isspace(*cp1) && !(strstr(cp1 + 1,":<"))) {
break;
}
}
if(arglen) {
for(cmdp = cmdtable; cmdp->name; cmdp++) {
if(strnicmp(cmdp->name,cp,arglen) == 0) {
char *line, *cp2;
for(cp2 = cp1; *cp2 && isspace(*cp2); cp2++) ;
line = strxdup(cp2);
strcpy(mp->buf,line);
xfree(line);
(*cmdp->func)(mp);
goto loop;
}
}
}
/* Can't be a legal command */
usputs(mp->s,Badcmd);
}
log(mp->s,9983,"SMTP close");
xfree(mp->buf);
if(mp->system != NULLCHAR) {
xfree(mp->system);
}
if(mp->from != NULLCHAR) {
xfree(mp->from);
}
if(mp->data != NULLFILE) {
Fclose(mp->data);
}
if(mp->to != NULLLIST) {
del_list(mp->to);
}
close_s(s);
xfree(mp);
smtptick(NULL); /* start SMTP daemon immediately */
}